/* Orbas:
 *     A open source CORBA Specification implementation from Huihoo.
 *
 * Copyright 2002-2003 Huihoo.org, Inc. All Right Reserved.
 *
 * This software is licensed under LGPL license.
 * See terms of license at gnu.org.
 *
 * For more information, visit:
 *
 * http://www.huihoo.org/orbas
 */



package org.huihoo.orbas.orb.types;

/**
 * <p>Description: </p>
 * Implementation for Any.
 * <p>Copyright (c) 2002,2003</p>
 * <p>Company: <a href="http://www.huihoo.org/">huihoo.org</a></p>
 * @author <a href="http://www.huihoo.org/~mep">mep(mep@huihoo.com)</a>
 * @see <a href="http://www.huihoo.org/orbas">http://www.huihoo.org/orbas</a>
 * @version 1.0
 */


import com.cognition.util.j2me.DataTypeUtil;
import com.cognition.util.j2me.J2MESerializable;
import com.cognition.util.marshal.JavaPrimitiveInputStream;
import com.cognition.util.marshal.JavaPrimitiveOutputStream;
import java.io.IOException;
import org.huihoo.orbas.orb.cdr.*;
import org.omg.CORBA.TypeCode;
import org.omg.CORBA.TCKind;
import org.omg.CORBA.BAD_PARAM;
import org.omg.CORBA.BAD_OPERATION;
import org.omg.CORBA.BAD_TYPECODE;

public final class Any extends org.omg.CORBA.Any {
    
    private org.omg.CORBA.TypeCode typeCode;
    private java.lang.Object value;
    private org.omg.CORBA.ORB orb;

    public Any (org.omg.CORBA.ORB orb)
    {
        this.orb = orb;
        
        typeCode = orb.get_primitive_tc(org.omg.CORBA.TCKind.tk_null);
    }
        
    public TCKind kind()
    {
        return typeCode.kind();
    }

    public org.omg.CORBA.TypeCode type()
    {
        return typeCode;
    }

    public void type(org.omg.CORBA.TypeCode t)
    {
        typeCode = t;
        value = null;
    }

    public boolean equal(org.omg.CORBA.Any a) {
        
        if (a == null)
        {
           throw new BAD_PARAM("Null passed to Any equal operation");
        }

        if ( !typeCode.equal(a.type()) )
        {
            return false; 
        }
        
        
        //get the real type
        TypeCode tc = typeCode;
        
        try
        {
            while( tc.kind() == org.omg.CORBA.TCKind.tk_alias)
            tc = tc.content_type();
        }
        catch( org.omg.CORBA.TypeCodePackage.BadKind bk )
        {
            // does not happen
        }
        
        int kind = tc.kind().value();
        
        switch (kind)
        {
            case TCKind._tk_null: 
            case TCKind._tk_void:
                return true;
            case TCKind._tk_short:
                return extract_short() == a.extract_short();
            case TCKind._tk_long:
                return extract_long() == a.extract_long();
            case TCKind._tk_longlong:
                return extract_longlong() == a.extract_longlong();
            case TCKind._tk_ushort:
                return extract_ushort() == a.extract_ushort();
            case TCKind._tk_ulong:
                return extract_ulong() == a.extract_ulong();
            case TCKind._tk_ulonglong:
                return extract_ulonglong() == a.extract_ulonglong();
            case TCKind._tk_float:
                return extract_float() == a.extract_float();
            case TCKind._tk_double:
                return extract_double() == a.extract_double();
            case TCKind._tk_fixed:
                throw new org.omg.CORBA.NO_IMPLEMENT();
//              return;
            case TCKind._tk_longdouble:
                throw new org.omg.CORBA.NO_IMPLEMENT();
//              return;
            case TCKind._tk_boolean:
                return extract_boolean() == a.extract_boolean();
            case TCKind._tk_char:
                return extract_char() == a.extract_char();
            case TCKind._tk_wchar:
                return extract_wchar() == a.extract_wchar();
            case TCKind._tk_octet:
                return extract_octet() == a.extract_octet();
            case TCKind._tk_any:
                return extract_any().equals( a.extract_any() );
            case TCKind._tk_TypeCode:
                return extract_TypeCode().equal( a.extract_TypeCode() );
            case TCKind._tk_Principal:
                throw new org.omg.CORBA.NO_IMPLEMENT ("Principal deprecated");
            case TCKind._tk_objref:
                return extract_Object().equals( a.extract_Object() );
            case TCKind._tk_string:
                return extract_string().equals( a.extract_string() );
            case TCKind._tk_wstring:
                return extract_wstring().equals( a.extract_wstring() );
            case TCKind._tk_array:
            case TCKind._tk_sequence:
            case TCKind._tk_struct: 
            case TCKind._tk_except:
            case TCKind._tk_enum:
            case TCKind._tk_union:
            {
                CDROutputStream out1, out2;
                
                out1 = new CDROutputStream(orb);
                out2 = new CDROutputStream(orb);
                
                write_value( out1 );
                a.write_value( out2 );

                return DataTypeUtil.equals(    out1.getBuffer(),
                                               out2.getBuffer());

            }
            default:
                throw new BAD_TYPECODE("Cannot compare anys with TypeCode kind " + kind);
        } 
    }

    public void read_value(org.omg.CORBA.portable.InputStream is, 
                    org.omg.CORBA.TypeCode type) {
        //get the real type
        TypeCode tc = type;
        
        this.typeCode = type;
        
        try
        {
            while( tc.kind() == org.omg.CORBA.TCKind.tk_alias)
            tc = tc.content_type();
        }
        catch( org.omg.CORBA.TypeCodePackage.BadKind bk )
        {
            // does not happen
        }
        
        int kind = tc.kind().value();
        
        switch (kind) {
            case TCKind._tk_null:
            case TCKind._tk_void:
                value = null;
                return;
            case TCKind._tk_short:
                value = new Short(is.read_short());
                return;
            case TCKind._tk_long:
                value = new Integer(is.read_long());
                return;
            case TCKind._tk_ushort:
                value = new Short(is.read_ushort());
                return;
            case TCKind._tk_ulong:
                value = new Integer(is.read_ulong());
                return;
            case TCKind._tk_float:
                value = new Float(is.read_float());
                return;
            case TCKind._tk_double:
                value = new Double(is.read_double());
                return;
            case TCKind._tk_boolean:
                value = new Boolean(is.read_boolean());
                return;
            case TCKind._tk_char:
                value = new Character(is.read_char());
                return;
            case TCKind._tk_octet:
                value = new Byte(is.read_octet());
                return;
            case TCKind._tk_TypeCode:
                value = is.read_TypeCode();
                return;
            case TCKind._tk_Principal:
                throw new org.omg.CORBA.NO_IMPLEMENT("Principal deprecated");
//              return;
            case TCKind._tk_objref:
                value = is.read_Object();
                //it's not enough,we must set ids
                //so that we can compare it with is_equivalent
                org.huihoo.orbas.orb.types.ObjectImpl impl = (org.huihoo.orbas.orb.types.ObjectImpl)value;
                
                try {
                    String[] ids = new String[2];
                    ids[0] = "IDL:org/omg/Object:1.0";
                    ids[1] = this.typeCode.id();
                    
                    impl.set_ids(ids);
                    value = impl;
                }
                catch(org.omg.CORBA.TypeCodePackage.BadKind e) {
                    System.out.println("Any read_value : Bad Interface TypeCode");
                }
                
                return;
            case TCKind._tk_string:
                value = is.read_string();
                return;
            case TCKind._tk_longlong:
                value = new Long(is.read_longlong());
                return;
            case TCKind._tk_ulonglong:
                value = new Long(is.read_ulonglong());
                return;
            case TCKind._tk_longdouble:
                throw new org.omg.CORBA.NO_IMPLEMENT();
//              return;
            case TCKind._tk_wchar:
                value = new Character(is.read_wchar());
                return;
            case TCKind._tk_wstring:
                value = is.read_wstring();
                return;
            case TCKind._tk_any:
                if(value == null)
                    value = orb.create_any();
                ((Any)value).read_value(is, is.read_TypeCode());
                return;
            case TCKind._tk_abstract_interface:
                throw new org.omg.CORBA.NO_IMPLEMENT();
//              return;
            case TCKind._tk_local_interface:
                throw new org.omg.CORBA.NO_IMPLEMENT();
//              return;
            case TCKind._tk_fixed:
                throw new org.omg.CORBA.NO_IMPLEMENT();
//              return;
            case TCKind._tk_value:
                throw new org.omg.CORBA.NO_IMPLEMENT();
//              return;
            case TCKind._tk_value_box:
                throw new org.omg.CORBA.NO_IMPLEMENT();
//              return;
            case TCKind._tk_enum:
                value = new Integer(is.read_ulong());
                return;
            case TCKind._tk_except:
            case TCKind._tk_struct:
            case TCKind._tk_sequence:
            case TCKind._tk_array:
                //dont know how to implement
                CDROutputStream out = new CDROutputStream(orb);
                
                //extract typecode and read every member from inputstream
                try {
                    for( int i = 0; i < tc.member_count(); i++ ) {
                        org.omg.CORBA.Any mem = orb.create_any();
                        
                        mem.read_value(is, tc.member_type(i));
                        mem.write_value(out);
                        
                        mem = null;
                    }
                }
                catch(org.omg.CORBA.TypeCodePackage.BadKind eb) {
                    System.out.println("Read any Error: " + eb.toString());
                }
                catch(org.omg.CORBA.TypeCodePackage.Bounds ex) {
                    System.out.println("Read any Error: " + ex.toString());
                }
                
                value = out;
                return;
            case TCKind._tk_union:
                CDROutputStream unionOut = new CDROutputStream(orb);
                
                //read discriminator
                try {
                        org.omg.CORBA.Any discriminator = orb.create_any();
                        discriminator.read_value(is, tc.discriminator_type());
                        discriminator.write_value(unionOut);
                        
                        boolean flag = false;
                        
                        for( int i = 0; i < tc.member_count(); i++ ) {
                            
                            if( tc.member_label(i).equal(discriminator) ) {
                                org.omg.CORBA.Any mem = orb.create_any();
                                mem.read_value(is, tc.member_type(i));
                                
                                mem.write_value(unionOut);
                                
                                mem = null;
                                flag = true;
                                
                                break;
                            }
                            
                        }
                        
                        if( flag == false ) {
                            System.out.println("Any : No Such Discriminator Value");
                        }
                        
                }
                catch(org.omg.CORBA.TypeCodePackage.BadKind eb) {
                    System.out.println("Read any Error: " + eb.toString());
                }
                catch(org.omg.CORBA.TypeCodePackage.Bounds ex) {
                    System.out.println("Read any Error: " + ex.toString());
                }
                
                value = unionOut;
                return;
            case TCKind._tk_alias:
            case TCKind._tk_native:
            default:
                //error
                System.out.println("Any Invalid TCKind code read: " + kind);
                return;
        }
    }
    
    public void write_value(org.omg.CORBA.portable.OutputStream os) {
        
        //get the real type
        TypeCode tc = typeCode;
        
        try
        {
            while( tc.kind() == org.omg.CORBA.TCKind.tk_alias)
            tc = tc.content_type();
        }
        catch( org.omg.CORBA.TypeCodePackage.BadKind bk )
        {
            // does not happen
        }
        
        int kind = tc.kind().value();
        
        switch (kind) {
            case TCKind._tk_null:
            case TCKind._tk_void:
                return;
            case TCKind._tk_short:
                os.write_short(((Short)value).shortValue());
                return;
            case TCKind._tk_ushort:
                os.write_ushort(((Short)value).shortValue());
                return;
            case TCKind._tk_long:
                os.write_long(((Integer)value).intValue());
                return;
            case TCKind._tk_ulong:
                os.write_ulong(((Integer)value).intValue());
                return;
            case TCKind._tk_float:
                os.write_float(((Float)value).floatValue());
                return;
            case TCKind._tk_double:
                os.write_double(((Double)value).doubleValue());
                return;
            case TCKind._tk_boolean:
                os.write_boolean(((Boolean)value).booleanValue());
                return;
            case TCKind._tk_char:
                os.write_char(((Character)value).charValue());
                return;
            case TCKind._tk_octet:
                os.write_octet(((Byte)value).byteValue());
                return;
            case TCKind._tk_TypeCode:
                os.write_TypeCode((TypeCode)value);
                return;
            case TCKind._tk_Principal:
                throw new org.omg.CORBA.NO_IMPLEMENT("Principal deprecated");
    //          return;
            case TCKind._tk_objref:
                os.write_Object((org.omg.CORBA.Object)value);
                return;
            case TCKind._tk_string:
                os.write_string((String)value);
                return;
            case TCKind._tk_longlong:
                os.write_longlong(((Long)value).longValue());
                return;
            case TCKind._tk_ulonglong:
                os.write_ulonglong(((Long)value).longValue());
                return;
            case TCKind._tk_longdouble:
                throw new org.omg.CORBA.NO_IMPLEMENT();
                //return;
            case TCKind._tk_wchar:
                os.write_wchar(((Character)value).charValue());
                return;
            case TCKind._tk_wstring:
                os.write_wstring((String)value);
                return;      
            case TCKind._tk_any:
                os.write_TypeCode(((Any)value).type());
                ((Any)value).write_value(os);
                return;
            case TCKind._tk_abstract_interface:
                throw new org.omg.CORBA.NO_IMPLEMENT();
//              return;
            case TCKind._tk_local_interface:
                throw new org.omg.CORBA.NO_IMPLEMENT();
//              return;
            case TCKind._tk_value:
                throw new org.omg.CORBA.NO_IMPLEMENT();
    //          return;
            case TCKind._tk_value_box:
                throw new org.omg.CORBA.NO_IMPLEMENT();
    //          return;
            case TCKind._tk_enum:
                os.write_ulong(((Integer)value).intValue());
                return;
            case TCKind._tk_fixed:
                throw new org.omg.CORBA.NO_IMPLEMENT();
    //          return;
            case TCKind._tk_struct:
            case TCKind._tk_union:
            case TCKind._tk_except:
            case TCKind._tk_sequence:
            case TCKind._tk_array:
                if( !(value instanceof CDROutputStream) ) {
                    System.out.println("Internal Error of Any");
                }
                
//                try {
//                    for( int i = 0; i < tc.member_count(); i++ ) {
//                        org.omg.CORBA.Any mem = orb.create_any();
//                        
//                        mem.read_value(is, tc.member_type(i));
//                        mem.write_value(out);
//                    }
//                }
//                catch(org.omg.CORBA.TypeCodePackage.BadKind eb) {
//                    System.out.println("Read any Error: " + eb.toString());
//                }
//                catch(org.omg.CORBA.TypeCodePackage.Bounds ex) {
//                    System.out.println("Read any Error: " + ex.toString());
//                }
                
                CDROutputStream out = (CDROutputStream)value;
                os.write_octet_array(out.getBuffer(), 0, out.getLength() - 1);
                return;
            case TCKind._tk_alias:
            case TCKind._tk_native:
            default:
                //error;
                System.out.println("Any Invalid TCKind code write: " + kind);
                return;
        }
    }

    public org.omg.CORBA.portable.OutputStream create_output_stream() {
        
        value = new CDROutputStream(orb);
        
        return (CDROutputStream)value;
    }
    
    public org.omg.CORBA.portable.InputStream create_input_stream() {
        
        CDROutputStream out;
        out = new CDROutputStream(orb);
        write_value(out);

        return new CDRInputStream(orb, out.getBuffer());
    }

    public short extract_short() {
        
        checkTypeCode(TCKind._tk_short);
        
        if (value instanceof CDROutputStream) {
           return create_input_stream().read_short();
        }
        
        return ((Short)value).shortValue();
    }
    
    public void insert_short(short s) {
        
        value = new Short(s);
        typeCode = orb.get_primitive_tc(TCKind.tk_short);
    }

    public int extract_long() {
        
        checkTypeCode(TCKind._tk_long);
        
        if (value instanceof CDROutputStream) {
           return create_input_stream().read_long();
        }
        
        return ((Integer)value).intValue();
    }
    
    public void insert_long(int i) {
        
        value = new Integer(i);
        typeCode = orb.get_primitive_tc (TCKind.tk_long);
    }

    public long extract_longlong() {
        
        checkTypeCode(TCKind._tk_longlong);
        
        if (value instanceof CDROutputStream) {
           return create_input_stream().read_longlong();
        }
        
        return ((Long)value).longValue();
    }
    
    public void insert_longlong(long l) {
        
        value = new Long(l);
        typeCode = orb.get_primitive_tc (TCKind.tk_longlong);
    }

    public short extract_ushort() {
        
        checkTypeCode(TCKind._tk_ushort);
        
        if (value instanceof CDROutputStream) {
           return create_input_stream().read_ushort();
        }
        
        return ((Short)value).shortValue();
    }
    
    public void insert_ushort(short s) {
        
        value = new Short(s);
        typeCode = orb.get_primitive_tc (TCKind.tk_ushort);
    }

    public int extract_ulong() {
        
        checkTypeCode(TCKind._tk_ulong);
        
        if (value instanceof CDROutputStream) {
           return create_input_stream().read_ulong();
        }
        
        return ((Integer)value).intValue();
    }
    
    public void insert_ulong(int i) {
        
        value = new Integer(i);
        typeCode = orb.get_primitive_tc (TCKind.tk_ulong);
    }

    public long extract_ulonglong() {
        
        checkTypeCode(TCKind._tk_ulonglong);
        
        if (value instanceof CDROutputStream) {
           return create_input_stream().read_ulonglong();
        }
        
        return ((Long)value).longValue();
    }
    
    public void insert_ulonglong(long l) {
        
        value = new Long(l);
        typeCode = orb.get_primitive_tc (TCKind.tk_ulonglong);
    }

    public float extract_float() {
        
        checkTypeCode(TCKind._tk_float);
        
        if (value instanceof CDROutputStream) {
           return create_input_stream().read_float();
        }
        
        return ((Float)value).floatValue();
        
    }
    
    public void insert_float(float f) {
        
        value = new Float(f);
        typeCode = orb.get_primitive_tc (TCKind.tk_float);
    }

    public double extract_double() {
        
        checkTypeCode(TCKind._tk_double);
        
        if (value instanceof CDROutputStream) {
           return create_input_stream().read_double();
        }
        
        return ((Double)value).doubleValue();
    }
    
    public void insert_double(double d) {
        
        value = new Double(d);
        typeCode = orb.get_primitive_tc (TCKind.tk_double);
    }

    public boolean extract_boolean() {
        
        checkTypeCode(TCKind._tk_boolean);
        
        if (value instanceof CDROutputStream) {
           return create_input_stream().read_boolean();
        }
        
        return ((Boolean)value).booleanValue();
    }
    
    public void insert_boolean(boolean b) {
        
        value = new Boolean(b);
        typeCode = orb.get_primitive_tc (TCKind.tk_boolean);
    }

    public char extract_char() {
        
        checkTypeCode(TCKind._tk_char);
        
        if (value instanceof CDROutputStream) {
           return create_input_stream().read_char();
        }
        
        return ((Character)value).charValue();
    }
    
    public void insert_char(char c) {
        
        value = new Character(c);
        typeCode = orb.get_primitive_tc (TCKind.tk_char);
    }

    public char extract_wchar() {
        
        checkTypeCode(TCKind._tk_wchar);
        
        if (value instanceof CDROutputStream) {
           return create_input_stream().read_wchar();
        }
        
        return ((Character)value).charValue();
    }
    
    public void insert_wchar(char c) {
        
        value = new Character(c);
        typeCode = orb.get_primitive_tc (TCKind.tk_wchar);
    }

    public byte extract_octet() {
        
        checkTypeCode(TCKind._tk_octet);
        
        if (value instanceof CDROutputStream) {
           return create_input_stream().read_octet();
        }
        
        return ((Byte)value).byteValue();
    }
    
    public void insert_octet(byte b) {
        
        value = new Byte(b);
        typeCode = orb.get_primitive_tc (TCKind.tk_octet);
    }

    public org.omg.CORBA.Any extract_any() {
        
        checkTypeCode(TCKind._tk_any);
        
        if (value instanceof CDROutputStream) {
           return create_input_stream().read_any();
        }
        
        return (org.omg.CORBA.Any)value;
    }
    
    public void insert_any(org.omg.CORBA.Any a) {
        
        value = a;
        typeCode = orb.get_primitive_tc (TCKind.tk_any);
    }

    public org.omg.CORBA.Object extract_Object() {
        
        checkTypeCode(TCKind._tk_objref);
        
        if (value instanceof CDROutputStream) {
           return create_input_stream().read_Object();
        }
        
        return (org.omg.CORBA.Object)value;
    }
    
    public void insert_Object(org.omg.CORBA.Object obj) {
        
        value = obj;

        String typeId = null;
        String name = "";

        if( value == null ) {
           typeId = "IDL:omg.org/CORBA/Object:1.0";
           name = "Object";
        }
        else {
           typeId = ((org.omg.CORBA.portable.ObjectImpl)obj)._ids()[0];

           // check if the repository Id is in IDL format
           if (typeId.startsWith ("IDL:")) {
              // parse the name from the repository Id string
              name = typeId.substring (4, typeId.lastIndexOf (':'));
              name = name.substring (name.lastIndexOf ('/') + 1);
           }
        }
        
        typeCode = orb.create_interface_tc( typeId , name );
    }


    public void insert_Object(org.omg.CORBA.Object obj,
                        org.omg.CORBA.TypeCode type) {
        
        value = obj;
        this.typeCode = type;
    }

    public String extract_string() {
        
        checkTypeCode(TCKind._tk_string);
        
        return value.toString ();
    }
    
    public void insert_string(String s) {
        
        value = s;
        typeCode = orb.create_string_tc(0);
    }

    public String extract_wstring() {
        
        checkTypeCode(TCKind._tk_wstring);
        
        return value.toString ();
    }
    
    public void insert_wstring(String value) {
        
        this.value = value;
        typeCode = orb.create_wstring_tc(0);
    }

    public TypeCode extract_TypeCode() {
        
        checkTypeCode(TCKind._tk_TypeCode);
        
        if (value instanceof CDROutputStream) {
           return create_input_stream().read_TypeCode();
        }
        
        return (org.omg.CORBA.TypeCode)value;
    }
    
    public void insert_TypeCode(TypeCode value) {
        
        this.value = value;
        typeCode = orb.get_primitive_tc (TCKind.tk_TypeCode);
    }

    
    private void checkTypeCode(int kind) {
        
        try {
            if (typeCode.content_type().kind().value() != kind) {
                throw new BAD_OPERATION("None Compatible typecode");
            }
        }
        catch(org.omg.CORBA.TypeCodePackage.BadKind e) {
            return;
        }
        catch(org.omg.CORBA.NO_IMPLEMENT ex) {
            return;
        }
    }

    public J2MESerializable extract_Value() {
        throw new org.omg.CORBA.NO_IMPLEMENT();
    }

    public void insert_Value(J2MESerializable v) {
        throw new org.omg.CORBA.NO_IMPLEMENT();
    }

    public void insert_Value(J2MESerializable v, TypeCode t) {
        throw new org.omg.CORBA.NO_IMPLEMENT();
    }

}